package ua.edu.sumdu.j2se.roman.lab1.domain;


import java.io.Serializable;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
 * Author: Radko Roman.
 */

/**
 * The following class a container for some tasks that described in TaskClass.
 * With next methods can perform the following manipulations with tasks:
 * <p/>
 * - add method is adds to ArrayTaskList object tasks.
 * <p/>
 * - remove method is delete task from container.
 * <p/>
 * - size method gets count of the task in container.
 * <p/>
 * - incoming method returns the arrays of the task with start time that
 * contained in time interval from initial time point to final time point.
 * <p/>
 * - toArray method returns array of the task with length that equal count tasks in container.
 * <p/>
 * Also this class implements Iterable and Cloneable interface.
 */
public class ArrayTaskList extends TaskList implements Serializable {

    /**
     * This method adds new task to the task list.
     *
     * @param task new task to be added, not null
     * @throws IllegalArgumentException when task is null
     */
    @Override
    public void add(Task task) {
        // in case if adding element equal null
        if (task == null) {
            throw new IllegalArgumentException("Task shouldn't be null");
        }
        // if the array is full
        if (size() == elements.length) {
            // create buffer array with size equal elements.length
            Task[] temp = elements;
            // increase size by two
            elements = new Task[2 * elements.length];
            // copy old elements
            for (int i = 0; i < temp.length; i++) {
                elements[i] = temp[i];
            }
        }
        // save task in the first free cell
        elements[firstFreeCell++] = task;
    }

    
    /**
     * 
     */
    public void clear() {
        firstFreeCell = 0;
        elements = new Task[START_SIZE];
    }

    /**
     * This method removes the task from the list.
     * If task is not in list - do nothing.
     *
     * @param task task that you need to remove from the list, not null
     * @throws  IllegalArgumentException when the task is null
     */
    @Override
    public void remove(Task task) {
        // in case if deleting element equal null
        if (task == null) {
            throw new IllegalArgumentException("Task shouldn't be null ");
        }
        int taskIndex = -1;
        for (int i = 0; i < size(); i++) {
            if (task.equals(elements[i])) {
                taskIndex = i;
                break;
            }
        }
        if (taskIndex != -1) {
            for (int i = taskIndex + 1; i < size(); i++) {
                elements[i - 1] = elements[i];
            }
            elements[firstFreeCell--] = null;
        }
    }

    /**
     * This method implements Iterable interface.
     *
     * @return  @Code{Iterator<Task>}
     */
    @Override
    public Iterator<Task> iterator() {
        return new Iterator<Task>() {
            int index = -1;
            boolean isLastActionRemove = false;

            /**
             * Returns true if the iteration has more elements.
             *
             * @return  true if next would return an element rather than throwing an exception.
             */
            @Override
            public boolean hasNext() {
                return index + 1 < size();
            }

            /**
             * Returns the next element in the iteration.
             *
             * @return the next element in the iteration.
             * @throws NoSuchElementException throws when the iteration has no more elements.
             */
            @Override
            public Task next() {
                if (!hasNext()) {
                    throw new NoSuchElementException("Iteration has no more elements");
                }
                isLastActionRemove = false;
                return elements[++index];
            }

            /**
             * Removes from the underlying collection the last element returned by the iterator.
             * This method can be called only once per call to next.
             * The behavior of an iterator is unspecified if the underlying collection is modified
             * while the iteration is in progress in any way other than by calling this method.
             *
             * @throws IllegalStateException 	throws if the next method has not yet been called, or the remove
             * 									method has already been called after the last call to the next method.
             */
            @Override
            public void remove() {
                if (isLastActionRemove) {
                    throw new IllegalStateException("Next method has not yet been called, or the remove method has already been called after the last call to the next method");
                }
                ArrayTaskList.this.remove(elements[index--]);
                isLastActionRemove = true;
            }
        };
    }

    /**
     * This method return the size of the list.
     *
     * @return size of the list
     */
    @Override
    public int size() {
        return firstFreeCell;
    }

    /**
     * This method performs duplicating of object TaskList type, with means creating a new object identical to current.
     *
     * @return clone of current list
     * @throws CloneNotSupportedException Thrown to indicate that the clone method in class Object has been called to clone an
     *                                    object, but that the object's class does not implement the Cloneable interface.
     */
    @Override
    public TaskList clone() throws CloneNotSupportedException {
        ArrayTaskList result = (ArrayTaskList) super.clone();
        result.elements = new Task[this.elements.length];
        result.firstFreeCell = 0;
        for (Task task: this) {
            result.add(task);
        }
        return result;
    }

    /**
     * This constant determines start size of the tasks array.
     */
    private final int START_SIZE = 10;

    /**
     * This variable indicates on the end of the task array.
     */
    private int firstFreeCell = 0;

    /**
     * Tasks array.
     */
    private Task[] elements = new Task[START_SIZE];

}

   